//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include <unistd.h>
#include <fcntl.h>

#include <time.h>
#include <errno.h>

#include <sys/stat.h>
#include <sys/times.h>
#include <sys/wait.h>

#include <iostream>
#include <fstream>

#include "libraries.h"
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
#define  LENGTHTEXT                 10000


#define  DIRECTORYDOMAIN            "IntraDomain"

#define  NAMEFILEFREQ               "ListFrequencies.ByLigand.IntraLigands.ComplexesCATHDomain.Binding.OnlyLigand.%d.profile.dat"
#define  NAMEFILESPLITPROFILE       "%s.IntraLigands.ComplexesCATHDomain.Binding.%d.%s.profile.dat"
#define  NAMEFILELIGANDPROFILE      "%s.IntraLigands.ComplexesCATHDomain.Binding.OnlyLigand.%d.profile.dat"

#define  DIRECTORYDATABYLIGAND      "DataByLigand"
#define  DIRECTORYALLLIGAND         "AllLigands"
#define  DIRECTORYLIGANDS           "Ligand"
#define  DIRECTORYOUT               ".."

#define  MINFREQLIGAND              10
#define  MINEPITOPELIGAND           4

#define  MAXTOPOLOGICALLEVEL        4
#define  NUMBERRESIDUESEXTEND       6

#define  TMPFILENAME                "tmp.txt"

#define  PROGRAM_DELDUPLLIG         "bin/DeleteInLigandFASTAProfileDuplication"
#define  PROGRAM_GETEXTENDALLBS     "bin/GetExtendedAllForBindingRegion"
#define  PROGRAM_GETFREQRESIDUE     "bin/GetFrequencyOfResidues"
#define  PROGRAM_GETFREQLENGTH      "bin/GetFrequencyOfLength"

#define  PROGRAM_PRAT2              "extern/Pratt2.1/pratt"
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
typedef char t_string [LENGTHTEXT];
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
using namespace std;
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
void panic (const char*);
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
int main (int argc, char** argv) {
  
  String* filenameDirectories       = NULL;
  String* filenameLogFile           = NULL;
  String* pathToProteinLINGOProject = NULL;
  String* pathToCATHFastaProfile    = NULL;
  
  if (argc < 5) {
    
    cout << "Error in the input parameters! Must by like: " << endl;
    cout << "./PipeProcessGetPatternsFromCATHSSCHPHMT <In File - List of Directories to process>";
    cout <<                                         " <Log File>";
    cout <<                                         " <Path to Protein LINGO Project executable>";
    cout <<                                         " <Path to CATH Fasta Profile File>";
    cout << endl;
    
    return 0;
    
  }
  else {
    
    filenameDirectories       = new String(argv[1]);
    filenameLogFile           = new String(argv[2]);
    pathToProteinLINGOProject = new String(argv[3]);
    pathToCATHFastaProfile    = new String(argv[4]);
    
    cout << "------------------------------------------------------------------------------------------------------" << endl;
    cout << " In File - List of Directories to process : " << argv[1] << endl;
    cout << "                                 Log File : " << argv[2] << endl;
    cout << " Path to Protein LINGO Project executable : " << argv[3] << endl;
    cout << "          Path to CATH Fasta Profile File : " << argv[4] << endl;
    cout << "------------------------------------------------------------------------------------------------------" << endl;
    
  }
  
  pathToProteinLINGOProject->Trim();
  
  //Directory with the name of folder to process (the folder with the information of residues near to the ligands ordered by distance in angstrom)
  ifstream directoriesFile (filenameDirectories->Out());
  if (!directoriesFile.is_open()) return EXIT_FAILURE;
  cout << "Opening the file with the directories to process - " << filenameDirectories->Out() << endl;
  
  //File to store the steps in the programs.
  ofstream logFile (filenameLogFile->Out());
  if (!logFile.is_open()) { directoriesFile.close(); return EXIT_FAILURE; }
  cout << "Opening the log file" << endl;
  
  char    buffer [LENGTHTEXT + 1];
  String* bufferString = new String ();
  
  //Loop across the folders
  while (!directoriesFile.eof()) {
    
    directoriesFile.getline(buffer, LENGTHTEXT);
    
    bufferString->In(buffer);
    bufferString->Trim();
    
    //Changing to a directory of data by angstrom (instance - 3)
    if (chdir(bufferString->Out()) == -1) panic ("Error changing directory");
    logFile << "Changing to a directory of data " << bufferString->Out() << endl;
    cout    << "Changing to a directory of data " << bufferString->Out() << endl;
    
    int folderNumber = atoi(bufferString->Out());
    
    //Changing to the directory IntraDomain
    if (chdir(DIRECTORYDOMAIN) == -1) panic("Error changing directory");
    logFile << "Changing to a directory " << DIRECTORYDOMAIN << endl;
    cout    << "Changing to a directory " << DIRECTORYDOMAIN << endl;

    //Open the file of ligand frequencies to decide what of their process (with frequency higher to a define constants - MINFREQLIGAND)
    sprintf(buffer, NAMEFILEFREQ, folderNumber);
    logFile << "Preparing to open the file of frequencies " << buffer << endl;
    cout    << "Preparing to open the file of frequencies " << buffer << endl;
    
    ifstream frequencyLigandFile (buffer);
    
    if (!frequencyLigandFile.is_open()) { 
      logFile << "Error opening the file: " << buffer << endl;
      cout    << "Error opening the file: " << buffer << endl;
      continue;
    }
    logFile << "Successful opening of file " << buffer << endl;
    cout    << "Successful opening of file " << buffer << endl;
    
    //Changing to the directory DataByLigand
    if (chdir(DIRECTORYDATABYLIGAND) == -1) panic("Error changing directory");
    logFile << "Changing to a directory " << DIRECTORYDATABYLIGAND << endl;
    cout    << "Changing to a directory " << DIRECTORYDATABYLIGAND << endl;

    //Changing to the directory Ligand
    if (chdir(DIRECTORYLIGANDS) == -1) panic("Error changing directory");
    logFile << "Changing to a directory " << DIRECTORYLIGANDS << endl;
    cout    << "Changing to a directory " << DIRECTORYLIGANDS << endl;
    
    while (!frequencyLigandFile.eof()) { 
      
      int frequency = 0, cumulativeFreq = 0;
      
      frequencyLigandFile >> buffer >> frequency;
      
      if (frequency < MINFREQLIGAND) continue; 

      bufferString->In(buffer);
      bufferString->Trim();
      
      if (bufferString->Length() != 3) continue;
      
      char cwd[10240];
      if (getcwd(cwd, sizeof(cwd)) != NULL)
        fprintf(stdout, "Current working dir: %s\n", cwd);
      cout << bufferString->Out() << " AAAA" << endl;
      
      //Changing to the directory of specific Ligand
      if (chdir(bufferString->Out()) == -1) panic("Error changing directory");
      logFile << "Changing to a directory " << bufferString->Out() << endl;
      cout    << "Changing to a directory " << bufferString->Out() << endl;

      for (int i = 0; i <= MAXTOPOLOGICALLEVEL; i++) {
        
        String folder;
        char   code;
        
        switch (i) {
          case 0  : folder.In("CATHSOLI"); code = 'I'; break;
          case 1  : folder.In("CATHSOL");  code = 'L'; break;
          case 2  : folder.In("CATHSO");   code = 'O'; break;
          case 3  : folder.In("CATHS");    code = 'S'; break;
          case 4  : folder.In("CATH");     code = 'H'; break;
          case 5  : folder.In("CAT");      code = 'T'; break;
          case 6  : folder.In("CA");       code = 'A'; break;
          case 7  : folder.In("C");        code = 'C'; break;
          default : folder.In("CATHSOLI"); code = 'I'; break;
        }
        
        //Changing to the directory of topological level
        if (chdir(folder.Out()) == -1) panic("Error changing directory");
        logFile << "Changing to a directory " << folder.Out() << endl;
        cout    << "Changing to a directory " << folder.Out() << endl;
        
        bool condSlash = (pathToProteinLINGOProject->Out()[pathToProteinLINGOProject->Length() - 1] == '/')?true:false;
        
        if (!condSlash) pathToProteinLINGOProject->Add("/");
        
        //Get the group of different data base on the Topological CATH Code using the Program DeleteInLigandFASTAProfileDuplication
        sprintf(buffer, "ls > %s\0", TMPFILENAME);
        system(buffer);
        
        ifstream tmpFile (TMPFILENAME);
        if (!tmpFile.is_open()) {
          
          logFile << "Error opening the file: " << buffer << endl;
          cout    << "Error opening the file: " << buffer << endl;
          
          //Changing to the directory Ligand
          if (chdir(DIRECTORYOUT) == -1) panic("Error changing directory");
          logFile << "Changing to a directory " << DIRECTORYOUT << endl;
          cout    << "Changing to a directory " << DIRECTORYOUT << endl;

          continue;
          
        }

        int  counter, numberDiffRecords = -1;
        
        while (!tmpFile.eof()) {
          tmpFile >> buffer;
          counter = sscanf(buffer, "%d.%*s.IntraLigands.ComplexesCATHDomain.Binding.%*d.CATHSOLI.profile.dat%*s", &numberDiffRecords);
          if (counter == 1) break;
        }

        sprintf(buffer, "rm %s\0", TMPFILENAME);
        system(buffer);
        
        if (numberDiffRecords < MINEPITOPELIGAND) {
            
          //Changing to the directory Ligand
          if (chdir(DIRECTORYOUT) == -1) panic("Error changing directory");
          logFile << "Changing to a directory " << DIRECTORYOUT << endl;
          cout    << "Changing to a directory " << DIRECTORYOUT << endl;

          continue;
          
        }

        for (int j = 0; j < 4; j++) {
          
          String category;
          
          switch (j) {
            case 0  : category.In("CH"); break;
            case 1  : category.In("PH"); break;
            case 2  : category.In("MT"); break;
            case 3  : category.In("SS"); break;
            default : category.In("CH"); break;
          }
          
          //Get the patterns with the Pratt 2.1 program
          sprintf(buffer, "cp %s.IntraLigands.ComplexesCATHDomain.Binding.%d.%s.Extended.%s.dat input\0", bufferString->Out(), folderNumber, folder.Out(), category.Out());
          system(buffer);

          ofstream fileSetPratt ("Pratt.set");
          if (!fileSetPratt.is_open()) {
            logFile << "Error opening the file: " << buffer << endl;
            cout    << "Error opening the file: " << buffer << endl;
            continue;
          }
          
          if (!strcmp(category.Out(), "CH")) {
            fileSetPratt << "A" << endl << "B" << endl << "C" << endl << "D" << endl << "E" << endl << "F" << endl << "G" << endl << "H" << endl;
          }
          else if (!strcmp(category.Out(), "PH")) {
            fileSetPratt << "A" << endl << "B" << endl << "C" << endl << "D" << endl << "E" << endl << "F" << endl << "G" << endl;
          }
          else if (!strcmp(category.Out(), "MT")) {
            fileSetPratt << "A" << endl << "B" << endl << "C" << endl << "D" << endl << "E" << endl;
            fileSetPratt << "F" << endl << "G" << endl << "H" << endl << "I" << endl << "J" << endl;
            fileSetPratt << "K" << endl << "L" << endl << "M" << endl << "N" << endl << "O" << endl;
            fileSetPratt << "P" << endl << "Q" << endl << "R" << endl << "S" << endl << "T" << endl;
            fileSetPratt << "U" << endl << "V" << endl << "W" << endl << "X" << endl << "Y" << endl;
          }
          else if (!strcmp(category.Out(), "SS")) {
            fileSetPratt << "H" << endl << "C" << endl << "E" << endl;
          }
          
          fileSetPratt.close();
          
          //90%
          sprintf(buffer, "%s%s \0",  pathToProteinLINGOProject->Out(), PROGRAM_PRAT2);
          sprintf(buffer, "%s fasta input -C%% 90 -PL 50 -PN 50 -PX 5 -FN 3 -FL 5 -FP 10 -BI ON -BF Pratt.set -RG ON -OF output -ON 5000 -OA 0 \0", buffer);
          system(buffer);      

          sprintf(buffer, "cp output %s.IntraLigands.ComplexesCATHDomain.Binding.%d.%s.Extended.%s.Pratt2.1.90P.dat\0", bufferString->Out(), folderNumber, folder.Out(), category.Out());
          system(buffer);      

          //80%
          sprintf(buffer, "%s%s \0",  pathToProteinLINGOProject->Out(), PROGRAM_PRAT2);
          sprintf(buffer, "%s fasta input -C%% 80 -PL 50 -PN 50 -PX 5 -FN 3 -FL 5 -FP 10 -BI ON -BF Pratt.set -RG ON -OF output -ON 5000 -OA 0 \0", buffer);
          system(buffer);      

          sprintf(buffer, "cp output %s.IntraLigands.ComplexesCATHDomain.Binding.%d.%s.Extended.%s.Pratt2.1.80P.dat\0", bufferString->Out(), folderNumber, folder.Out(), category.Out());
          system(buffer);      

          //60%
          sprintf(buffer, "%s%s \0",  pathToProteinLINGOProject->Out(), PROGRAM_PRAT2);
          sprintf(buffer, "%s fasta input -C%% 60 -PL 50 -PN 50 -PX 5 -FN 3 -FL 5 -FP 10 -BI ON -BF Pratt.set -RG ON -OF output -ON 5000 -OA 0 \0", buffer);
          system(buffer);      

          sprintf(buffer, "cp output %s.IntraLigands.ComplexesCATHDomain.Binding.%d.%s.Extended.%s.Pratt2.1.60P.dat\0", bufferString->Out(), folderNumber, folder.Out(), category.Out());
          system(buffer);      

          //40%
          sprintf(buffer, "%s%s \0",  pathToProteinLINGOProject->Out(), PROGRAM_PRAT2);
          sprintf(buffer, "%s fasta input -C%% 40 -PL 50 -PN 50 -PX 5 -FN 3 -FL 5 -FP 10 -BI ON -BF Pratt.set -RG ON -OF output -ON 5000 -OA 0 \0", buffer);
          system(buffer);      

          sprintf(buffer, "cp output %s.IntraLigands.ComplexesCATHDomain.Binding.%d.%s.Extended.%s.Pratt2.1.40P.dat\0", bufferString->Out(), folderNumber, folder.Out(), category.Out());
          system(buffer);      

          //20%
          sprintf(buffer, "%s%s \0",  pathToProteinLINGOProject->Out(), PROGRAM_PRAT2);
          sprintf(buffer, "%s fasta input -C%% 20 -PL 50 -PN 50 -PX 5 -FN 3 -FL 5 -FP 10 -BI ON -BF Pratt.set -RG ON -OF output -ON 5000 -OA 0 \0", buffer);
          system(buffer);      

          sprintf(buffer, "cp output %s.IntraLigands.ComplexesCATHDomain.Binding.%d.%s.Extended.%s.Pratt2.1.20P.dat\0", bufferString->Out(), folderNumber, folder.Out(), category.Out());
          system(buffer);      

          sprintf(buffer, "rm input output report Pratt.set\0");
          system(buffer);      
      
        }
        
        //Changing to the directory Ligand
        if (chdir(DIRECTORYOUT) == -1) panic("Error changing directory");
        logFile << "Changing to a directory " << DIRECTORYOUT << endl;
        cout    << "Changing to a directory " << DIRECTORYOUT << endl;
        
      }            
      
      //Changing to the directory Ligand
      if (chdir(DIRECTORYOUT) == -1) panic("Error changing directory");
      logFile << "Changing to a directory " << DIRECTORYOUT << endl;
      cout    << "Changing to a directory " << DIRECTORYOUT << endl;

    }
    
    frequencyLigandFile.close();
    
  }
  
  directoriesFile.close();
  logFile.close();
  
  if (bufferString)              delete bufferString;
  
  if (filenameDirectories)       delete filenameDirectories;
  if (filenameLogFile)           delete filenameLogFile;
  if (pathToProteinLINGOProject) delete pathToProteinLINGOProject;
  if (pathToCATHFastaProfile)    delete pathToCATHFastaProfile;

  return EXIT_SUCCESS;
  
}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
void panic (const char *str) {
  
  t_string s;

  cout << str << endl;
  
  write(2, str, strlen(str));
  write(2, "\n", 1);
  
  if (errno != 0) {
    
    sprintf(s, "%d %s\n", errno, strerror(errno));
    write(2, s, strlen(s));
    
  }
  
  exit(0);
  
}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
